#ifndef SERVERSOCK_H
#define SERVERSOCK_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "GeneralSock.h"
#include "MsgModPC.h"

#include <string>

using std::string;

#define PORT 2020
#define MSG_SOCKET_RECV 1061
#define MSG_SOCKET_NEW  1060
#define MSG_SOCKET_HUNGUP 1062
#define MSG_SOCKET_ERROR 1063


class CServerSocket
{
public:
	void RegisterMsg(T_ModuleDescriptor md)
	{
		MD = md;
	}
    void ThreadStart()
    {
        DWORD id;
        CreateThread (NULL, 0, Start, (PVOID)this, 0, &id);
    }
    static DWORD WINAPI Start( PVOID p )
    {
        CServerSocket *ss = (CServerSocket *)p;
        string &Name = ss->Name;
        /* master file descriptor list */
        fd_set &master = ss->master;
        /* temp file descriptor list for select() */
        fd_set &read_fds = ss->read_fds;
        /* server address */
        struct sockaddr_in &serveraddr = ss->serveraddr;
        /* client address */
        struct sockaddr_in &clientaddr = ss->clientaddr;
        /* maximum file descriptor number */
        int &fdmax = ss->fdmax;
        /* listening socket descriptor */
        int &listener = ss->listener;
        /* newly accept()ed socket descriptor */
        int &newfd = ss->newfd;
        /* buffer for client data */
        char * buf = ss->buf;
        int &nbytes = ss->nbytes;
        /* for setsockopt() SO_REUSEADDR, below */
        int &yes = ss->yes;
        int &addrlen = ss->addrlen;
        int &i = ss->i, &j = ss->j;
		T_ModuleDescriptor &MD = ss->MD;

        /* clear the master and temp sets */
        FD_ZERO(&master);

        FD_ZERO(&read_fds);
        /* get the listener */

        if((listener = socket(AF_INET, SOCK_STREAM, 0)) == -1)
        {
            //perror("Server-socket() error lol!");
			if (MD != -1) POST_MSG_TO(MD, MSG_SOCKET_ERROR, -1, "Server-socket() error lol!");
            /*just exit lol!*/
            return 0;
        }

        printf("Server-socket() is OK...\n");
        /*"address already in use" error message */
        if(setsockopt(listener, SOL_SOCKET, SO_REUSEADDR,(char *) &yes, sizeof(int)) == -1)
        {
            //perror("Server-setsockopt() error lol!");
			if (MD != -1) POST_MSG_TO(MD, MSG_SOCKET_ERROR, -1, "Server-setsockopt() error lol!");
            return 0;
        }
        printf("Server-setsockopt() is OK...\n");
        /* bind */
        serveraddr.sin_family = AF_INET;
        serveraddr.sin_addr.s_addr = INADDR_ANY;
        serveraddr.sin_port = htons(PORT);
        memset(&(serveraddr.sin_zero), '\0', 8);

        if(bind(listener, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) == -1)
        {
            //perror("Server-bind() error lol!");
			if (MD != -1) POST_MSG_TO(MD, MSG_SOCKET_ERROR, -1, "Server-bind() error lol!");
            return 0;
        }
        printf("Server-bind() is OK...\n");
        /* listen */
        if(listen(listener, 10) == -1)
        {
           // perror("Server-listen() error lol!");
			if (MD != -1) POST_MSG_TO(MD, MSG_SOCKET_ERROR, -1, "Server-listen() error lol!");
            return 0;
        }
        printf("Server-listen() is OK...\n");
        /* add the listener to the master set */
        FD_SET(listener, &master);
        /* keep track of the biggest file descriptor */
        fdmax = listener; /* so far, it's this one*/
        /* loop */
        for(;;)
        {
            /* copy it */
            read_fds = master;
            if(select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1)
            {
                //perror("Server-select() error lol!");MSG_SOCKET_ERROR
				if (MD != -1) POST_MSG_TO(MD, MSG_SOCKET_ERROR, -1, "Server-select() error lol!");
                return 0;
            }
            //printf("Server-select() is OK...\n");
            /*run through the existing connections looking for data to be read*/

            for(i = 0; i <= fdmax; i++)
            {
                if(FD_ISSET(i, &read_fds))
                {
                    /* we got one... */
                    if(i == listener)
                    {
                        /* handle new connections */
                        addrlen = sizeof(clientaddr);

                        if((newfd = accept(listener, (struct sockaddr *)&clientaddr, &addrlen)) == -1)
                        {
                            perror("Server-accept() error lol!");
                        }
                        else
                        {
                            //printf("Server-accept() is OK...\n");

                            FD_SET(newfd, &master); /* add to master set */

                            if(newfd > fdmax)
                            {
                                /* keep track of the maximum */
                                fdmax = newfd;
                            }
                            //printf("%s: New connection from %s on socket %d\n", Name.c_str(), inet_ntoa(clientaddr.sin_addr), newfd);
							if (MD != -1) POST_MSG_TO(MD, MSG_SOCKET_NEW, newfd, (char *)0);
						}
                    }
                    else
                    {
                        /* handle data from a client */
                        if((nbytes = recv(i, buf, 1024, 0)) <= 0)
                        {
                            /* got error or connection closed by client */

							if(nbytes == 0) {}
                                /* connection closed */
                                //printf("%s: socket %d hung up\n", Name.c_str(), i);
                            else
							{}//perror("recv() error lol!");
							if (MD != -1) POST_MSG_TO(MD, MSG_SOCKET_HUNGUP, i, (char *)0);
                            /* close it... */
                            close(i);
                            /* remove from master set */
                            FD_CLR(i, &master);
                        }
                        else
                        {
							if (MD != -1) POST_MSG_TO(MD, MSG_SOCKET_RECV, i, DataFlow(buf, nbytes));                                 
                        }
                    }
                }
            }
        }

        return 0;
    }


    CServerSocket() : yes(1), Name("server"), MD(-1) {}
private:
    string Name;
    /* master file descriptor list */
    fd_set master;
    /* temp file descriptor list for select() */
    fd_set read_fds;
    /* server address */
    struct sockaddr_in serveraddr;
    /* client address */
    struct sockaddr_in clientaddr;
    /* maximum file descriptor number */
    int fdmax;
    /* listening socket descriptor */
    int listener;
    /* newly accept()ed socket descriptor */
    int newfd;
    /* buffer for client data */
    char buf[1024];
    int nbytes;
    /* for setsockopt() SO_REUSEADDR, below */
    int yes;
    int addrlen;
    int i, j;
	T_ModuleDescriptor MD;
};


















#endif